﻿using Microsoft.AspNetCore.Mvc;
using Urs.Core;
using Urs.Core.Caching;
using ExternalAuth.WeixinOpen.Models;
using Urs.Services.Configuration;
using Urs.Services.Users;
using Urs.Services.Logging;
using Urs.Services.Media;
using Urs.Framework.Controllers;
using System;
using System.Collections.Generic;
using Weixin.UrSDK.App;
using ExternalAuth.WeixinOpen.Core;
using Urs.Data.Domain.Configuration;
using Urs.Services.Authentication.External;
using Urs.Services.Authentication;
using Urs.Data.Domain.Users;
using System.Threading.Tasks;
using Weixin.SDK;

namespace ExternalAuth.WeixinOpen.Controllers
{
    /// <summary>
    /// 微信授权
    /// </summary>
    [ApiVersion("1.0")]
    [Route("api/v{version:apiVersion}/weixinopen")]
    [ApiController]
    public class WeixinOpenController : BaseApiController
    {
        private readonly ISettingService _settingService;
        private readonly ICacheManager _cacheManager;
        private readonly ILogger _logger;
        private readonly WeixinOpenSettings _weixinOpenSettings;
        private readonly IUserService _userService;
        private readonly IPictureService _pictureService;
        private readonly UserSettings _userSettings;
        private readonly IOpenAuthenticationService _openAuthenticationService;
        private readonly IAuthenticationService _authenticationService;
        private readonly IUserRegistrationService _userRegistrationService;
        /// <summary>
        /// 构造器
        /// </summary>
        public WeixinOpenController(
            ISettingService settingService,
            ICacheManager cacheManager,
            ILogger logger,
            WeixinOpenSettings weixinOpenSettings,
            IUserService userService,
            IPictureService pictureService,
            UserSettings userSettings,
            IOpenAuthenticationService openAuthenticationService,
            IAuthenticationService authenticationService,
            IUserRegistrationService userRegistrationService)
        {
            this._settingService = settingService;
            this._cacheManager = cacheManager;
            this._logger = logger;
            this._weixinOpenSettings = weixinOpenSettings;
            this._userService = userService;
            this._pictureService = pictureService;
            this._userSettings = userSettings;
            this._openAuthenticationService = openAuthenticationService;
            this._authenticationService = authenticationService;
            this._userRegistrationService = userRegistrationService;
        }

        #region Methods
        /// <summary>
        /// 更新昵称、头像[Auth]
        /// </summary>
        /// <param name="update">对象</param>
        /// <returns></returns>
        [ApiAuthorize]
        [HttpPost("update")]
        public ApiResponse Update(MoUpdate update)
        {
            var user = RegisterUser;
            if (user == null || user.Deleted)
                return ApiResponse.Warn("用户不存在");

            if (!string.IsNullOrEmpty(update.nickName))
                user.Nickname = update.nickName;
            if (!string.IsNullOrEmpty(update.avatarUrl))
                user.AvatarPictureId = _pictureService.DownloadPictureUrl(update.avatarUrl);

            _userService.UpdateUser(user);

            return ApiResponse.Success();
        }

        static Dictionary<string, ApiResponse<TokenEntity>> collection = new Dictionary<string, ApiResponse<TokenEntity>>();
        private readonly object @lock = new object();
        /// <summary>
        /// 微信授权接口
        /// </summary>
        /// <param name="code"></param>
        /// <param name="state"></param>
        /// <param name="encryptedData"></param>
        /// <param name="iv"></param>
        /// <returns></returns>
        [HttpGet("login")]
        public ApiResponse<TokenEntity> LoginApi(string code, string state, string encryptedData = "", string iv = "")
        {
            ApiResponse<TokenEntity> result = null;
            var secondRequest = false;
            lock (@lock)
            {
                secondRequest = collection.ContainsKey(code);
            }

            if (!secondRequest)
            {
                //第一次请求
                lock (@lock)
                {
                    collection[code] = null;
                }
            }
            else
            {
                //第二次请求
                lock (@lock)
                {
                    result = collection[code];
                }
            }
            try
            {
                var oiask = new AppOAuth2API().GetOpenIdAndSessionKey(code, _weixinOpenSettings.AppId, _weixinOpenSettings.AppSecret);

                if (oiask == null)
                    return ApiResponse<TokenEntity>.Warn("回调内容异常");

                if (!string.IsNullOrEmpty(oiask.errmsg))
                    return ApiResponse<TokenEntity>.Warn(string.Format("回调异常,errcode:{0} errmsg:{1}", oiask.errcode, oiask.errmsg));
                var parameters = new OAuthAuthParameters(Provider.SystemName);
                parameters.OpenId = oiask.openid;
                parameters.OAuthToken = oiask.session_key;
                parameters.OpenId = oiask.openid;
                parameters.OAuthToken = oiask.session_key;
                var userFound = _openAuthenticationService.GetUser(parameters);
                //客户不存在新创建
                if (userFound == null)
                {
                    var user = new AppOAuth2API().GetUser(encryptedData, iv, oiask.session_key) ?? new WeixinAppUserInfo();

                    parameters.UserClaim.Nickname = user.nickName;
                    parameters.UserClaim.HeadImgUrl = user.avatarUrl;
                    parameters.UserClaim.Sex = user.gender;
                    parameters.UserClaim.Province = user.province;
                    parameters.UserClaim.City = user.city;
                    parameters.UnionId = user.unionId;
                    userFound = _userService.InsertGuestUser();
                    _openAuthenticationService.AssociateExternalAccountWithUser(userFound, parameters);

                    _userRegistrationService.RegisterUser(request: new UserRegistrationRequest()
                    {
                        User = userFound,
                        IsApproved = true,
                        PasswordFormat = PasswordFormat.Clear,
                        UserRegistrationType = UserRegistrationType.AutoToken,
                    });
                }
                if (!string.IsNullOrEmpty(state))
                {
                    var inviteUser = _userService.GetUserByCode(state);
                    if (inviteUser != null && inviteUser.Active && !inviteUser.Deleted)
                    {
                        userFound.AffiliateId = inviteUser.Id;
                        _userService.UpdateUser(userFound);
                    }
                }

                var token = _authenticationService.JwtSignIn(userFound, _userSettings.JwtSecurityKey, _userSettings.JwtExpires, _userSettings.JwtIssuer, _userSettings.JwtAudience);

                var model = new TokenEntity() { token = token, openId = oiask.openid, guid = userFound.UserGuid.ToString() };

                result = ApiResponse<TokenEntity>.Success(model);
            }
            catch (Exception ex)
            {
                _logger.Error(ex.Message, ex);
                return ApiResponse<TokenEntity>.Warn(ex.Message);
            }
            if (result != null)
            {
                lock (@lock)
                {
                    collection[code] = result;
                }
            }
            return result;
        }
        /// <summary>
        /// 微信获取手机号
        /// </summary>
        /// <param name="code"></param>
        /// <param name="encryptedData"></param>
        /// <param name="iv"></param>
        /// <returns></returns>
        [HttpGet("phonenumber")]
        public ApiResponse<PhoneEntity> GetPhoneNumber(string code, string encryptedData, string iv)
        {
            var oiask = new AppOAuth2API().GetOpenIdAndSessionKey(code, _weixinOpenSettings.AppId, _weixinOpenSettings.AppSecret);

            if (oiask == null)
            {
                _logger.Error(Newtonsoft.Json.JsonConvert.SerializeObject(oiask));
                return ApiResponse<PhoneEntity>.Warn("回调异常");
            }
            if (!string.IsNullOrEmpty(oiask.errmsg))
            {
                var error = string.Format("回调异常,errcode:{0} errmsg:{1}", oiask.errcode, oiask.errmsg);
                _logger.Error(error);
                return ApiResponse<PhoneEntity>.Warn(error);
            }

            var parameters = new OAuthAuthParameters(Provider.SystemName);
            parameters.OpenId = oiask.openid;
            parameters.OAuthToken = oiask.session_key;
            var auth = _openAuthenticationService.GetExternalAuthentication(parameters);

            if (auth != null)
            {
                var api = new AppOAuth2API().GetPhoneNumber(encryptedData, iv, oiask.session_key);

                if (api == null)
                    return ApiResponse<PhoneEntity>.Warn("获取不到手机号");

                return ApiResponse<PhoneEntity>.Success(new PhoneEntity() { phone = api.phoneNumber, openId = parameters.OpenId });
            }
            return ApiResponse<PhoneEntity>.Warn("未登录授权");
        }


        [HttpPost("createQRCode")]
        public async Task<WeixinResult> createQRCode(WxacodeRequest request)
        {
            if (request == null)
                return new WeixinResult()
                {
                    IsSuccess = false,
                    Msg = "无参数",
                };

            var data = Newtonsoft.Json.JsonConvert.SerializeObject(request);

            var accessToken = BasicAPI.GetAccessToken(_weixinOpenSettings.AppId, _weixinOpenSettings.AppSecret);

            var result = new AppOAuth2API().CreateWXaQRCode(data, access_token: accessToken);

            return await result;
        }
        [HttpPost("get")]
        public async Task<WeixinResult> get(WxacodeRequest request)
        {
            if (request == null)
                return new WeixinResult()
                {
                    IsSuccess = false,
                    Msg = "无参数",
                };

            var data = Newtonsoft.Json.JsonConvert.SerializeObject(request);

            var accessToken = BasicAPI.GetAccessToken(_weixinOpenSettings.AppId, _weixinOpenSettings.AppSecret);

            var result = new AppOAuth2API().GetWXaCode(data, access_token: accessToken);

            return await result;
        }

        [HttpPost("getUnlimited")]
        public async Task<WeixinResult> getUnlimited(WxacodeRequest request)
        {
            if (request == null)
                return new WeixinResult()
                {
                    IsSuccess = false,
                    Msg = "无参数",
                };

            var data = Newtonsoft.Json.JsonConvert.SerializeObject(request);

            var accessToken = BasicAPI.GetAccessToken(_weixinOpenSettings.AppId, _weixinOpenSettings.AppSecret);

            var result = new AppOAuth2API().GetWXaCodeUnLimit(data, access_token: accessToken.access_token);

            return await result;
        }
        #endregion
    }
}